unit ORM.ConsultJson;

interface

uses
  Data.DBXJSON, ORM.Base;

type
  TConsultJson = class
  private
    class procedure LoadRelatedObjects( pObject : TJSonVO );
  public
    class function Consult<T : class>( const pSQLCommand : string; pFilter : string; pPage : Integer ): TJSONArray; overload;
    class function Consult<T : class>( const pFilter : string; pPage : Integer ): TJSONArray; overload;
  end;

implementation

uses
  DBXCommon, ORM.Utils, ORM.Drive.Connection, ORM.Base.ObjectDBX, SysUtils, Rtti,
  DBXJSONReflect, ORM.Attributes, TypInfo;

class function TConsultJson.Consult<T>(const pSQlCommand : string; pFilter: string; pPage: Integer): TJSONArray;
var
  FiltroSQL: String;
  DBXCommand: TDBXCommand;
  DBXReader: TDBXReader;
  Obj: T;
begin
  Result := TJSONArray.Create;
  pFilter := FormataFiltro(pFilter);

  if pFilter <> '' then
    FiltroSQL := ' WHERE ' + pFilter;

  try
    DBXCommand := TConnectionDBX.GetConnection.DBXConnection.CreateCommand;
    DBXCommand.Text := pSQlCommand + FiltroSQL;
    DBXCommand.Prepare;
    DBXReader := DBXCommand.ExecuteQuery;

    while DBXReader.Next do
    begin
      Obj := TObjectDBX.LoadObjectFomDBXReader<T>(DBXReader);
      try
        Result.AddElement(TJSonVO.ObjectToJSON<T>(Obj));
      finally
        TObject(Obj).Free;
      end;
    end;
  finally
    FreeAndNil(DBXCommand);
    FreeAndNil(DBXReader);
  end;
end;

class function TConsultJson.Consult<T>(const pFilter: string; pPage: Integer): TJSONArray;
var
  ObjConsulta: TObject;
  Obj: T;
  DBXReader: TDBXReader;
begin
  Result := TJSONArray.Create;

  ObjConsulta := TClass(T).Create;
  try
    DBXReader := TObjectDBX.GetDBXReader(ObjConsulta);
    try
      while DBXReader.Next do
      begin
        Obj := TObjectDBX.LoadObjectFomDBXReader<T>(DBXReader);
        try
          LoadRelatedObjects(TJSonVO(Obj));
          Result.AddElement(TJSonVO(Obj).ToJSON);
        finally
          TObject(Obj).Free;
        end;
      end;
    finally
      TObjectDBX.DealocateCommand;
    end;
  finally
    ObjConsulta.Free;
  end;
end;

class procedure TConsultJson.LoadRelatedObjects(pObject: TJSonVO);
var
  Contexto: TRttiContext;
  Tipo: TRttiType;
  TipoLista: TRttiType;
  Atributo: TCustomAttribute;
  Propriedade: TRttiProperty;
  NomeTipoObj: string;
  NomeClasseObj: string;
  UnMarshal: TJSONUnMarshal;
  I: Integer;
  Obj: TJSonVO;
  ItemLista: TJSonVO;
  DBXReader: TDBXReader;
  Lista: TObject;
begin
  Contexto := TRttiContext.Create;
  try
    Tipo := Contexto.GetType(pObject.ClassType);
    for Propriedade in Tipo.GetProperties do
    begin
      for Atributo in Propriedade.GetAttributes do
      begin
        if Atributo is TManyValuedAssociation then
        begin
          if Propriedade.PropertyType.TypeKind = tkClass then
          begin
            NomeTipoObj := Propriedade.PropertyType.Name;
            if (Pos('TList',NomeTipoObj) > 0) or (Pos('TObjectList',NomeTipoObj) > 0) then
            begin
              I := Pos('<',NomeTipoObj);
              NomeClasseObj := Copy(NomeTipoObj,I+1,Length(NomeTipoObj)-1-I);
              UnMarshal := TJSONUnMarshal.Create;
              try
                Obj := UnMarshal.ObjectInstance(Contexto,NomeClasseObj) as TJSonVO;
                if Assigned(Obj) then
                begin
                  Lista := Propriedade.GetValue(pObject).AsObject;
                  if Assigned(Lista) then
                  begin
                    TipoLista := Contexto.GetType(Lista.ClassType);
                    DBXReader := TObjectDBX.GetDBXReader(Obj);
                    try
                      while DBXReader.Next do
                      begin
                        ItemLista := Obj.NewInstance as TJSonVO;
                        ItemLista := VOFromDBXReader(ItemLista,DBXReader);
                        TipoLista.GetMethod('Add').Invoke(Lista,[ItemLista])
                      end;
                    finally
                      DBXReader.Free;
                    end;
                  end;
                  FreeAndNil(Obj);
                end;
              finally
                UnMarshal.Free;
              end;
            end;
          end;
        end
        else
        if Atributo is TAssociation then
        begin
          if Propriedade.PropertyType.TypeKind = tkClass then
          begin
            NomeClasseObj := Propriedade.PropertyType.QualifiedName;
            Obj := Propriedade.GetValue(pObject).AsObject as TJSonVO;
            if not Assigned(Obj) then
            begin
              UnMarshal := TJSONUnMarshal.Create;
              try
                Obj := UnMarshal.ObjectInstance(Contexto,NomeClasseObj) as TJSonVO;
              finally
                UnMarshal.Free;
              end;
            end;

            if Assigned(Obj) then
            begin
              DBXReader := TObjectDBX.GetDBXReader(Obj);
              try
                if DBXReader.Next then
                  Obj := VOFromDBXReader(Obj,DBXReader);
              finally
                DBXReader.Free;
              end;
              Propriedade.SetValue(pObject,Obj);
            end;
          end;
        end;
      end;
    end;
  finally
    Contexto.Free;
  end;
end;

end.
